<?php
/**
 * Created by PhpStorm.
 * User: rocky
 * Date: 2020-02-21
 * Time: 13:19
 */

namespace app\common\tools;


use think\facade\Request;

class LogThink
{
    protected $logPathDir;
    protected $filePath;
    protected $dataCount = 0;
    protected $limit = 10;
    public function __construct($filePath = null)
    {
        $this->logPathDir = app()->getRuntimePath() . 'log/';
        if (is_null($filePath)) {
            $this->filePath = $this->getLastModifiedLog();
        } else {
            $this->filePath = $filePath;
        }


    }

    public function getLogFiles($count = 20)
    {
        $files = glob($this->logPathDir . '*');
        $files = array_combine($files, array_map('filemtime', $files));
        arsort($files);
        $filesArr = [];
        foreach ($files as $file => $time) {
            $filesArr[] = [
                'path' => $file,
                'file_name' => basename($file),
                'size' => $this->getSize(filesize($file)),
                'update_time' => date('Y-m-d H:i:s', $time)
            ];
        }
        return array_slice($filesArr, 0, $count);
    }

    function getSize($filesize)
    {

        if ($filesize >= 1073741824) {

            $filesize = round($filesize / 1073741824 * 100) / 100 . ' GB';

        } elseif ($filesize >= 1048576) {

            $filesize = round($filesize / 1048576 * 100) / 100 . ' MB';

        } elseif ($filesize >= 1024) {

            $filesize = round($filesize / 1024 * 100) / 100 . ' KB';

        } else {

            $filesize = $filesize . ' 字节';

        }

        return $filesize;

    }

    public function getLastModifiedLog()
    {
        $logs = $this->getLogFiles();
        $logs = current($logs);
        return $logs['path'];
    }

    /**
     * Fetch logs by giving offset.
     *
     * @param int $seek
     * @param int $lines
     * @param int $buffer
     *
     * @return array
     *
     * @see http://www.geekality.net/2011/05/28/php-tail-tackling-large-files/
     */
    public function fetch($seek = 0, $lines = 20, $buffer = 4096,$filterContent='',$filterTime='')
    {
        $f = fopen($this->filePath, 'rb');
        if ($seek) {
            fseek($f, abs($seek));
        } else {
            fseek($f, 0, SEEK_END);
        }

        if (fread($f, 1) != "\n") {
            $lines -= 1;
        }
        fseek($f, -1, SEEK_CUR);

        // 从前往后读,上一页
        // Start reading
        if ($seek > 0) {
            $output = '';

            $this->pageOffset['start'] = ftell($f);

            while (!feof($f) && $lines >= 0) {
                $output = $output . ($chunk = fread($f, $buffer));
                $lines -= substr_count($chunk, "\n[20");
            }
            $this->pageOffset['end'] = ftell($f);

            while ($lines++ < 0) {
                $strpos = strrpos($output, "\n[20") + 1;
                $_ = mb_strlen($output, '8bit') - $strpos;
                $output = substr($output, 0, $strpos);
                $this->pageOffset['end'] -= $_;
            }

            // 从后往前读,下一页
        } else {
            $output = '';

            $this->pageOffset['end'] = ftell($f);

            while (ftell($f) > 0 && $lines >= 0) {
                $offset = min(ftell($f), $buffer);
                fseek($f, -$offset, SEEK_CUR);
                $output = ($chunk = fread($f, $offset)) . $output;
                fseek($f, -mb_strlen($chunk, '8bit'), SEEK_CUR);
                $lines -= substr_count($chunk, "\n[20");
            }

            $this->pageOffset['start'] = ftell($f);

            while ($lines++ < 0) {
                $strpos = strpos($output, "\n[20") + 1;
                $output = substr($output, $strpos);
                $this->pageOffset['start'] += $strpos;
            }
        }

        fclose($f);

        return $this->parseLog($output,$filterContent,$filterTime);
    }

    /**
     * Get previous page url.
     *
     * @return bool|string
     */
    public function getPrevPageUrl($filterContent='',$filterTime='')
    {

        if(!empty($filterContent) || !empty($filterTime)){
            $page = request()->get('page',1);
            if($page > 1){
                return url('') . '?' . http_build_query([
                        'file' => $this->filePath, 'page' => $page-1,
                ]);
            }else{
                return false;
            }
        }else{
            $filesize = $this->getFilesize();
            if ($this->pageOffset['end'] >= $filesize - 1) {
                return false;
            }
            return url('') . '?' . http_build_query([
                    'file' => $this->filePath, 'offset' => $this->pageOffset['end'],
                ]);
        }

    }

    /**
     * Get Next page url.
     *
     * @return bool|string
     */
    public function getNextPageUrl($filterContent='',$filterTime='')
    {
        if(!empty($filterContent) || !empty($filterTime)){
            $page = request()->get('page',1);
            if($this->dataCount < $this->limit){
                return false;
            }else{
                return url('') . '?' . http_build_query([
                        'file' => $this->filePath, 'page' => $page+1,
                    ]);
            }
        }else{
            if ($this->pageOffset['start'] == 0) {
                return false;
            }

            return url('') . '?' . http_build_query([
                    'file' => urlencode($this->filePath), 'offset' => -$this->pageOffset['start'],
                ]);
        }

    }

    public function getFilesize()
    {
        return filesize($this->filePath);
    }

    /**
     * Parse raw log text to array.
     *
     * @param $raw
     *
     * @return array
     */
    protected function parseLog($raw,$filterContent='',$filterTime='')
    {
        $logs = explode('---------------------------------------------------------------', $raw);
        if (empty($logs)) {
            return [];
        }
        $parsed = [];

        foreach ($logs as $log) {

            preg_match('/\[(.*)\]/U', $log, $arr);
            if(isset($arr[1])){
                $strtotime = strtotime($arr[1]);
                $time = date('Y年m月d日 H:i:s',$strtotime);
                $info = str_replace("[{$time}] ", '', $log);
                $info = trim($info);

                if (!empty($info)) {
                    if(!empty($filterContent) && !empty($filterTime)){
                        $dates = explode(' - ',$filterTime);

                        $date = date('Y-m-d',$strtotime);
                        if(stristr($info,$filterContent) !== false && ($dates[0] <= $date && $dates[1] >= $date)){
                            $parsed[] = [
                                'time' => $time,
                                'info' => trim($info),
                            ];
                        }
                    }elseif (!empty($filterContent)){
                        if(stristr($info,$filterContent) !== false){
                            $parsed[] = [
                                'time' => $time,
                                'info' => trim($info),
                            ];
                        }
                    }elseif (!empty($filterTime)){
                        $dates = explode(' - ',$filterTime);
                        $date = date('Y-m-d',$strtotime);
                        if($dates[0] <= $date && $dates[1] >= $date){
                            $parsed[] = [
                                'time' => $time,
                                'info' => trim($info),
                            ];
                        }
                    }else{
                        $parsed[] = [
                            'time' => $time,
                            'info' => trim($info),
                        ];
                    }

                }
            }

        }

        unset($logs);
        $this->limit = Request::get('limit',10);
        rsort($parsed);
        if(!empty($filterContent) || !empty($filterTime)){
            $page = request()->get('page',1);
            $page = $this->limit * ($page-1);
            $parsed = array_splice($parsed,$page, $this->limit );
        }
        $this->dataCount = count($parsed);
        return $parsed;
    }
}